package de.tum.in.bluetooth;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.os.Handler;
import android.util.Log;

public class BluetoothClient extends Thread 
{
	public final static int RECEIVED_DATA = 1;
	public final static int CONNECTED = 2;
	public final static int REQUESTED = 3;
	public final static int CONNECTING = 4;
	public final static int EXCEPTION = 5;
	public final static int DISCONNECTED = 6;
	
	protected boolean active;
	public boolean isConnected;
	protected Handler asyncHandler;
	
	protected BluetoothSocket socket;
	protected BluetoothDevice device;
	
	protected IBluetoothManager bluetoothDatahandler;
	//00001101-0000-1000-8000-00805F9B34FB
	//f5efb9d2-deaf-4af8-a304-8739fe2109ab
	protected UUID uid = UUID.fromString("f5efb9d2-deaf-4af8-a304-8739fe2109ab");
	
	public BluetoothClient(Handler messageHandler)
	{
		super();
		this.asyncHandler=messageHandler;
		
		active=true;
		isConnected=false;
	}
	
	public BluetoothClient(Handler messageHandler,BluetoothDevice toDevice)
	{
		super();
		this.asyncHandler=messageHandler;
		this.device = toDevice;
		
		active=true;
		isConnected=false;
	}
	
	public BluetoothClient(Handler messageHandler,BluetoothSocket targetSocket)
	{
		super();
		this.asyncHandler=messageHandler;
		this.socket = targetSocket;
		this.device = targetSocket.getRemoteDevice();
		isConnected=true;
		
		active=true;
	}

	public IBluetoothManager getBluetoothDatahandler() {
		return bluetoothDatahandler;
	}

	public void setBluetoothDatahandler(IBluetoothManager bluetoothDatahandler) {
		this.bluetoothDatahandler = bluetoothDatahandler;
	}

	public synchronized void cancel()
	{
		Log.i("BluetoothClient", "Cancel");
		if(socket!=null)
			try {
				socket.close();
				Log.i("BluetoothClient", "Canceled Connection to "+device.getName());
			} catch (IOException e) {
				Log.i("BluetoothClient", "Close error "+e.getMessage());
			}
		
		device = null;
		socket=null;
		
		active=false;
	}
	
	public void run() 
	{
		try
		{
			while(active)
			{
				if(!isConnected)
				{
					//Try to connect to server
					if(socket == null)
						socket = device.createRfcommSocketToServiceRecord(uid);
					
		            socket.connect();
		            isConnected=true;
				}
				else
				{
					//Wait for Messages
					this.receiveObject();
				}
			}
		}catch(Exception e)
		{
			handleError(e);
		}
	}
	
	public void disconnect()
	{
		if(socket!=null)
			try {
				socket.close();
				Log.i("BluetoothClient", "Disconnected from "+device.getName());
			} catch (IOException e) {
				Log.i("BluetoothClient", "Close error "+e.getMessage());
			}
		
		device = null;
		socket=null;
		isConnected=false;
	}
	
	public void sendObject(Object data)
	{	
		try 
		{
			OutputStream output = socket.getOutputStream();
			
			if(bluetoothDatahandler!=null)
				bluetoothDatahandler.sendObject(output, data);
			else
				if(data instanceof String)
					this.sendString((String)data);
            
            Log.i("BluetoothClient","<< "+data);
        } catch (IOException e) {
        	Log.i("BluetoothClient","Failed to send message "+data);
        	
        	if(asyncHandler!=null)
				asyncHandler.obtainMessage(EXCEPTION,"Client "+e.getMessage()).sendToTarget();
			
        }
	}
	
	public void sendString(String message)
	{
		try 
		{
			OutputStream output = socket.getOutputStream();
			output.write(message.getBytes());
            output.flush();
            
            Log.i("BluetoothClient","<< "+message);
        } catch (IOException e) {
        	Log.i("BluetoothClient","Failed to send message "+message);
        	
        	if(asyncHandler!=null)
				asyncHandler.obtainMessage(EXCEPTION,"Client "+e.getMessage()).sendToTarget();
			
        }
	}
	
	public void sendByte(int b)
	{
		try {
            socket.getOutputStream().write(b);
            
            Log.i("BluetoothClient","<< "+b);
        } catch (IOException e) {
        	Log.i("BluetoothClient","Failed to send message "+b);
        	
        	if(asyncHandler!=null)
				asyncHandler.obtainMessage(EXCEPTION,"Client "+e.getMessage()).sendToTarget();
			
        }
	}
	
	protected void receiveObject()
	{	
		Log.i("BluetoothClient","Try to receive Object");
        
        Object obj = null;
        
		try 
		{
			InputStream input = socket.getInputStream();
			
			if(bluetoothDatahandler!=null)
				obj = bluetoothDatahandler.receiveObject(input);
			else
			{
				byte[] buffer = new byte[1024];  // buffer store for the stream
		        int bytes;
		        
				bytes = input.read(buffer);
				
				obj = new String(buffer,0,bytes);
			}
			
			Log.i("BluetoothClient",">> "+obj);
			
			if(asyncHandler!=null)
				asyncHandler.obtainMessage(RECEIVED_DATA,obj).sendToTarget();
			
		} catch (IOException e) 
		{
			Log.i("BluetoothClient","Failed to receive Message"+e.getMessage());
			this.disconnect();
		}
	}
	
	public void handleError(Exception exception)
	{
		String deviceName="None";
		
		if(device!=null)
			deviceName = device.getName();
			
		
		System.out.println("Exception occured on client: "+ deviceName + " - "+exception);
		Log.i("Exception occured on client", deviceName + " - "+ exception);
		
		if(asyncHandler!=null)
			asyncHandler.obtainMessage(EXCEPTION,"Client "+exception.getMessage()).sendToTarget();
		
	}
	
}
